from typing import Union, Any
from bpy.types import Object, Collection
from ...addon.naming import FluidLabNaming


class CommonVars:

    """ Clase del Objeto para obtener (ondemand) las rutas/y/o items más utilizadas en el addon, de una manera más fácil y práctica """

    def __init__(self, context):
        self.context = context

    @property
    def view_layer(self):
        return self.context.view_layer

    @property
    def scn(self):
        return self.context.scene

    @property
    def fluidlab(self):
        return self.scn.fluidlab
    
    @property
    def rendering(self):
        return self.fluidlab.rendering

    @property
    def fluid_presets(self):
        return self.fluidlab.fluid_presets

    @property 
    def lists(self):
        return self.fluidlab.lists
    
    @property 
    def fluid_groups(self):
        return self.lists.fluid_groups
        
    @property 
    def fluid_interactions(self):
        return self.lists.fluid_interactions
    
    @property 
    def fluid_mesh(self):
        return self.lists.fluid_mesh
    
    @property 
    def fluid_colliders(self):
        return self.lists.fluid_colliders
    
    @property 
    def fluid_single_colliders(self):
        return self.lists.fluid_single_colliders
    
    @property
    def fluid_forces_groups(self):
        return self.lists.fluid_forces_groups

    @property
    def ui(self):
        return self.fluidlab.ui

    @property
    def toggles(self):
        return self.ui.toggles
    
    @property
    def shader_props(self):
        return self.fluidlab.shader_props



def get_common_vars(context, **kwargs):
    """ 
    Devuelve una lista o única propiedad deseada para las variables solicitadas,
    según el contexto proporcionado a través del argumento "context".

    Ejemplos de uso:
        view_layer = get_common_vars(context, get_view_layer=True)
        scn, fluidlab = get_common_vars(context, get_scn=True, get_fluidlab=True)
    """

    cv = CommonVars(context)

    # Creamos una lista de propiedades permitidas, y en el orden que se solicitarían, excepto user_item que es la ultima.
    allowed_props = ["view_layer", "scn", "fluidlab", "rendering", "fluid_presets", "lists", "fluid_groups", "fluid_interactions", "fluid_mesh", "fluid_colliders", "fluid_single_colliders", "fluid_forces_groups", "ui", "toggles", "shader_props"]

    # Limpiamos los prefijos "get_" de los argumentos.
    kwargs_clean = {k.replace("get_", ""): v for k, v in kwargs.items()}

    # Creamos un diccionario solo con las propiedades permitidas y sus valores recopilados.
    props = {k: getattr(cv, k) for k in allowed_props if k in kwargs_clean and kwargs_clean[k]}

    # Incluyo los metodos especiales que reciben objetos por argumento:
    queries = ["get_user_item", "get_canvas_props", "get_brush_props", "get_dp_mod", "get_surfaces_list"]

    # si hay flag del usuario de debug:
    debug = kwargs.get("debug")

    for query in queries:
        if query not in kwargs:
            continue
        # ejecuto la funcion quey y le paso el objeto por argumento:
        ob = getattr(cv, query)(kwargs.get(query))

        # si algun query returna None:
        if ob is None:
            if debug:
                print("[DEBUG] User Query", query, "None")

        props[query] = ob

    if debug:
        # print("[DEBUG] Input User:", kwargs)
        print("[DEBUG] Output:", props)

    # Devolvemos los valores solicitados:
    if kwargs.get("get_all"):
        return [v for v in props.values()]
    else:
        # Con el popitem, si el len es igual a 1, devolvemos (del par k,v del diccionario) el value, y sino devolvemos la lista entera de valores.
        return list(props.values())[0] if len(props.values()) == 1 else list(props.values())
